<template>
  <q-page
    class="q-pa-md"
    @dragenter.stop.prevent=""
    @dragleave.stop.prevent=""
    @dragover.stop.prevent=""
    @drop.stop.prevent="onDrop"
  >
    <q-table
      :rows="filePaths"
      :columns="[
        { name: 'index', label: '#', field: 'index', align: 'left' },
        { name: 'fileName', label: '文件名', field: 'fileName', align: 'left' },
        { name: '分辨率', label: '分辨率', field: 'test', align: 'left' },
        { name: '视频编码', label: '视频编码', field: 'test', align: 'left' },
        { name: '音频信息', label: '音频信息', field: 'test', align: 'left' },
        {
          name: 'outputName',
          label: '输出文件名',
          field: 'outputName',
          align: 'left',
        },
        { name: '字幕', label: '字幕', field: 'subtitle', align: 'left' },
        { name: '进度', label: '进度', field: 'progress', align: 'left' },
      ]"
      :rows-per-page-options="[10, 20, 0]"
      row-key="fileName"
      no-data-label="拖入文件导入"
      flat
      bordered
    >
      <template #top-left>
        <q-btn
          :ripple="false"
          color="primary"
          icon-right="file_upload"
          label="导入"
          unelevated
        />
      </template>
      <template #top-right>
        <q-btn
          :loading="loading"
          :disable="filePaths.length < 1"
          :ripple="false"
          color="primary"
          icon-right="sync"
          label="开始转换"
          unelevated
          @click="onConvert"
        >
          <template #loading>
            处理中&nbsp;&nbsp;&nbsp;&nbsp;
            <q-spinner-rings size="1em" />
          </template>
        </q-btn>
      </template>
      <template #body="{ row, rowIndex }">
        <q-tr>
          <q-td key="index">{{ rowIndex + 1 }}</q-td>
          <q-td key="fileName">{{ row.fileName }}</q-td>
          <q-td key="分辨率">
            {{ row.fileInfo.video.width }} * {{ row.fileInfo.video.height }}
          </q-td>
          <q-td key="视频编码">
            {{ row.fileInfo.video.codec_name }}({{
              (parseInt(row.fileInfo.video.bit_rate) / 1000 / 1000).toFixed(2)
            }}Mbps/{{ row.fileInfo.video.avg_frame_rate }})
          </q-td>
          <q-td key="音频信息">
            <template v-for="d in row.fileInfo.audio">
              {{ d.codec_name }}({{
                Math.round(parseInt(d.bit_rate) / 1024)
              }}k/{{ (parseFloat(d.sample_rate) / 1000).toFixed(1) }}kHz)
            </template>
          </q-td>
          <q-td key="outputName">
            <q-input v-model="row.outputName" />
          </q-td>
          <q-td key="字幕">
            {{ row.subtitleName }}
            <q-btn
              icon="search"
              size="sm"
              flat
              round
              @click="onChooseSubtitle(row)"
            />
          </q-td>
          <q-td key="进度">
            {{ row.progress === -1 ? `转换失败` : `${row.progress} %` }}
          </q-td>
        </q-tr>
      </template>
    </q-table>
    <q-input v-model="outputDir" label="保存目录" dense>
      <template v-slot:prepend>
        <q-icon name="folder" />
      </template>
      <template v-slot:append>
        <q-btn icon="search" size="sm" flat round @click="onOpenDirectory" />
        <q-btn icon="mode" size="sm" flat round @click="onChooseOutput" />
      </template>
    </q-input>
  </q-page>
</template>

<script setup lang="ts">
import { Ref, ref } from 'vue'
import { getFileInfo } from 'src/utils/ffprobe'
import type { FileInfo } from 'src/utils/ffprobe.d'
import { useQuasar } from 'quasar'
import { convert } from 'src/utils/handBrake'
import { mp4dash, mp4fragment } from 'src/utils/bento4'
import {
  getFileExtension,
  getFileNameAndFullName,
  replaceFileExtension,
} from 'src/utils/file'

defineOptions({
  name: 'IndexPage',
})

interface FilePaths {
  subtitle: string
  subtitleType: string
  subtitleName: string
  path: string
  fileName: string
  fileInfo: FileInfo
  progress: number
  outputName: string
  convertIndex: number
}

const filePaths: Ref<FilePaths[]> = ref([])
const loading = ref(false)
const $q = useQuasar()
const outputDir = ref(localStorage.outputDir || '/Users/v/Downloads/')
const presetList = ref([
  {
    name: '1080p hevc',
    command:
      '/usr/local/bin/HandBrakeCLI -Z "H.265 Apple VideoToolbox 1080p" --no-markers -x keyint=60:profile=main10 -q 50 --color-matrix 709 ',
  },
])

async function onDrop(e: DragEvent) {
  const files = e.dataTransfer?.files || []
  const failed: string[] = []
  for (let i = 0; i < files.length; i++) {
    // 导入文件
    let obj: FilePaths
    try {
      const fileInfo = await getFileInfo(files[i].path)
      const names = getFileNameAndFullName(files[i].path)
      obj = {
        path: files[i].path,
        fileName: names.fullName,
        fileInfo: fileInfo as FileInfo,
        progress: 0,
        outputName: names.fileName,
        convertIndex: 0,
        subtitle: '',
        subtitleName: '',
        subtitleType: '',
      }
    } catch (e) {
      failed.push(files[i].path + (e as { message: string }).message)
      continue
    }
    // 导入srt字幕
    const srtPath = replaceFileExtension(files[i].path, '.srt')
    const srtExists = NAS.fileExists(srtPath)
    const assPath = replaceFileExtension(files[i].path, '.ass')
    if (srtExists) {
      obj.subtitle = srtPath
      obj.subtitleType = 'srt'
      obj.subtitleName = getFileNameAndFullName(files[i].path).fullName
    } else {
      const assExists = NAS.fileExists(assPath)
      if (assExists) {
        obj.subtitle = assPath
        obj.subtitleType = 'ass'
        obj.subtitleName = getFileNameAndFullName(files[i].path).fullName
      }
    }
    filePaths.value.push(obj)
  }
  if (failed.length > 0) {
    $q.dialog({
      title: `${failed.length} 个文件导入失败`,
      message: failed
        .map((item, index) => {
          return `${index + 1}. ${item}`
        })
        .join('<br>'),
      html: true,
    })
  }
}

async function onConvert() {
  loading.value = true
  for (let i = 0; i < filePaths.value.length; i++) {
    const item = filePaths.value[i]
    // 转码
    try {
      let command = `${presetList.value[item.convertIndex].command} -i ${item.path} -o ${outputDir.value}${item.outputName}-hevc.mp4 `
      if (item.subtitleType) {
        switch (item.subtitleType) {
          case 'srt':
            command += `--srt-file ${item.subtitle} --srt-codeset UTF-8 --srt-burn`
            break
          case 'ass':
            command += `--ssa-file ${item.subtitle} --ssa-burn`
            break
        }
      }
      await convert(command, (type, data) => {
        if (type === 'progress') {
          item.progress = data as number
        } else if (type === 'close') {
          item.progress = data ? 100 : -1
        }
      })
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } catch (e) {
      $q.dialog({ title: (e as Error).message })
      continue
    }
    // fragment
    try {
      await mp4fragment(
        `${outputDir.value}${item.outputName}-hevc.mp4`,
        `${outputDir.value}${item.outputName}-fragment.mp4`,
      )
    } catch (e) {
      $q.dialog({ title: (e as Error).message })
      continue
    }
    // hls转换
    try {
      await mp4dash(
        `${outputDir.value}${item.outputName}-fragment.mp4`,
        `${outputDir.value}${item.outputName}`,
      )
    } catch (e) {
      $q.dialog({ title: (e as Error).message })
      continue
    }
    // 清理 hevc文件、 fragment
    await NAS.execSync(`rm -rf ${outputDir.value}${item.outputName}-hevc.mp4`)
    await NAS.execSync(
      `rm -rf ${outputDir.value}${item.outputName}-fragment.mp4`,
    )
  }
  loading.value = false
}

async function onChooseOutput() {
  const outputPath = (await NAS.chooseFolder()) + '/'
  localStorage.outputDir = outputPath
  outputDir.value = outputPath
}

function onOpenDirectory() {
  NAS.openDirectory(outputDir.value)
}

async function onChooseSubtitle(row: FilePaths) {
  const path = await NAS.openFile()
  console.log(path)
  row.subtitle = path
  row.subtitleName = getFileNameAndFullName(path).fullName
  row.subtitleType = getFileExtension(path)
}
</script>

<style lang="scss" scoped></style>
